package com.example.algorithm.test;

import org.aopalliance.intercept.MethodInterceptor;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.IntPredicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

/**
 * 数组中三个数的最大乘积
 * @auther lijiewei
 * @date 2024-03-19 20:11
 */
public class MaxProduct {

    /** 排序方式. */
    private int sort(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        return Math.max(nums[0]*nums[1]*nums[n-1], nums[n-3]*nums[n-2]*nums[n-1]);
    }

    @Test
    public void MaxProductTest() throws Exception{
        System.out.println(sort(new int[] {1, 2, 3, 4, 5, 6}));
    }

    /** 排序方式. */
    private int forEach(int[] nums) {
        int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
        int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
        for (int num : nums) {
            if(num > max1) {
                max3 = max2;
                max2 = max1;
                max1 = num;
            } else if (num > max2) {
                max3 = max2;
                max2 = num;
            } else if (num > max3) {
                max3 = num;
            }

            if (num < min1) {
                min2 = min1;
                min1 = num;
            } else if (num < min2) {
                min2 = num;
            }
        }
        return Math.max(min1*min2*max1, max1*max2*max3);
    }

    @Test
    public void forEachTest() throws Exception{
        System.out.println(forEach(new int[] {1, 2, 3, 4, 5, 6}));
    }

    /** 暴力解法. */
    private int[] forceSolution(int[] nums, int target) {
        int length = nums.length;
        for (int i = 0; i < length; i++) {
            for (int j = i+1; j < length; j++) {
                if (nums[i] + nums[j] == target) {
                    return new int[]{i, j};
                }
            }
        }
        return new int[]{};
    }

    /** 标记解法. */
    private int[] markSolution(int[] nums, int target) {
        Map<Integer, Integer> mark = new HashMap<>();

        int length = nums.length;
        for (int i = 0; i < length; i++) {
            Integer index = mark.get(target - nums[i]);
            if (null != index) {
                return new int[]{index, i};
            }
            mark.put(nums[i], i);
        }
        return new int[]{};
    }

    @Test
    public void sumTest() throws Exception{
        System.out.println(Arrays.toString(forceSolution(new int[]{1, 2, 3, 4, 5, 6}, 10)));
        System.out.println(Arrays.toString(markSolution(new int[]{1, 2, 3, 4, 5, 6}, 10)));
    }

    /** 二分查找. */
    private int[] binarySearch(int[] nums, int target) {
        int length = nums.length;
        for (int i = 0; i < length; i++) {
            int left = i, right = length-1;
            while (left <= right) {
                int middle = left + (right - left)/2;
                if (nums[middle] == target - nums[i]) {
                    return new int[] {i, middle};
                } else if (nums[middle] < target - nums[i]) {
                    left = middle + 1;
                } else {
                    right = middle - 1;
                }
            }

        }
        return new int[]{};
    }

    /** 双指针. */
    private int[] twoPoint(int[] nums, int target) {
        int left = 0, right = nums.length-1;
        while (left < right) {
            if (nums[left] + nums[right] == target) {
                return new int[]{left, right};
            } else if (nums[left] + nums[right] < target) {
                left++;
            } else {
                right--;
            }
        }
        return new int[]{};
    }

    @Test
    public void sumTest2() throws Exception{
        System.out.println(Arrays.toString(binarySearch(new int[]{1, 2, 3, 4, 5, 6}, 10)));
        System.out.println(Arrays.toString(twoPoint(new int[]{1, 2, 3, 4, 5, 6}, 10)));
    }

    public static int compare(int a, int b) {
        return Integer.compare(a, b);
    }

    @Test
    public void IntStreamTest() throws Exception{
        List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);

        Comparator<Integer> comparator = (a, b) -> MaxProduct.compare(a, b);
        Collections.sort(numbers, comparator);
        System.out.println(numbers);

        List<Integer> numbers2 = Arrays.asList(3, 1, 4, 1, 5, 9);
        Comparator<Integer> compare = MaxProduct::compare;
        Collections.sort(numbers2, compare);
        System.out.println(numbers2);

    }

    public int compareString(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }


    @Test
    public void compareTest() throws Exception{
        List<String> strings = Arrays.asList("apple", "banana", "cherry");

        Comparator<String> comparator = (a, b) -> new MaxProduct().compareString(a, b);
        Collections.sort(strings, comparator);
        System.out.println(strings);

        List<String> strings2 = Arrays.asList("apple", "banana", "cherry");
        Comparator<String> compare = new MaxProduct()::compareString;
        Collections.sort(strings2, compare);
        System.out.println(strings2);

    }

    @Test
    public void personTest() throws Exception{
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        Function<String, Person> function =  name -> new Person(name);
        List<Person> personList = names.stream().map(function).collect(Collectors.toList());
        System.out.println(personList);

        List<String> names2 = Arrays.asList("Alice", "Bob", "Charlie");
        Function<String, Person> function2 =  Person::new;
        List<Person> personList2 = names2.stream().map(function2).collect(Collectors.toList());
        System.out.println(personList2);
    }

    /** 暴力迭代. */
    private int forceRecursion(int num) {
        if (0 == num) {
            return 0;
        }
        if (1 == num) {
            return 1;
        }
        return forceRecursion(num-1) + forceRecursion(num-2);
    }

    @Test
    public void forceRecursionTest() throws Exception{
        //第11位，下标为10
        System.out.println(forceRecursion(10));
    }
}
